# -*- coding: utf-8 -*-
import hashlib
import json
import time
from datetime import datetime

import requests

from common.bankcard import db as bank_db
from common.bankcard.model import BANK_DCT
from common.mch import handler as mch_handler
from common.timer import TIMER_EVENT_TYPE
from common.timer.handler import submit_notify_event
from common.utils import track_logging
from common.utils.exceptions import ParamError
from common.withdraw import db as withdraw_db
from common.withdraw.model import WITHDRAW_ORDER_STATUS

_LOGGER = track_logging.getLogger('withdraw')

APP_CONF = {
    '8190979590': {  # dwc
        'API_KEY': 'Q3037rJrV74aKBbxEiNp',
        'GATEWAY': 'https://api.toppay.cc/open/api/payForShop.htm',
        'QUERY_GATEWAY': 'http://api.toppay.cc/open/api/getPaymentStatus.htm',
    },
    '8640228936': {  # 测试
        'API_KEY': '3mjKj3zd44CKzD7Ye9fj',
        'GATEWAY': 'https://api.cggcbb.com/open/api/payForShop.htm',
        'QUERY_GATEWAY': 'http://api.cggcbb.com/open/api/getPaymentStatus.htm',
    },
}


def _get_api_key(app_id):
    return APP_CONF[app_id]['API_KEY']


def _get_gateway(app_id):
    return APP_CONF[app_id]['GATEWAY']


def _get_query_gateway(app_id):
    return APP_CONF[app_id]['QUERY_GATEWAY']


def generate_sign(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        s += '%s=%s&' % (k, parameter[k])
    s += 'encryptKey=%s' % key
    m = hashlib.md5()
    m.update(s.encode('utf8'))
    sign = m.hexdigest().upper()
    _LOGGER.info('xinglongpay_withdraw sign_str sign: %s, %s', s, sign)
    return sign


def _build_query_string(params):
    s = ''
    for k in sorted(params.keys()):
        s += '%s=%s&' % (k, params[k])
    return s[:-1]


def verify_notify_sign(params, key):
    sign = params['sign']
    params.pop('sign')
    calculated_sign = generate_sign(params, key)
    if sign.upper() != calculated_sign.upper():
        _LOGGER.info("xinglongpay_withdraw sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


def create_order(order, channel):
    """兴隆下单"""
    app_id = channel.appid
    parameter_dict = {
        "name": order.pay_account_username,
        "idCardNo": '',
        "amount": str(order.amount),
        "cardNo": order.pay_account_num,
        "bankName": BANK_DCT[order.pay_account_bank],
        "bankId": '',
        "accessKey": app_id,
        "timestamp": int(time.time()),
        "remark": str(order.id),
    }
    parameter_dict['sign'] = generate_sign(parameter_dict, _get_api_key(app_id))
    # 先设置为三方未知状态
    order.status = WITHDRAW_ORDER_STATUS.THIRD_UNKNOWN
    order.third_type = channel.id
    order.save()
    _LOGGER.info('xinglongpay_withdraw create data: %s, %s', json.dumps(parameter_dict), _get_gateway(app_id))
    url = _get_gateway(app_id) + '?' + _build_query_string(parameter_dict)
    _LOGGER.info('xinglongpay_withdraw create url: %s', url)
    response = requests.get(url, timeout=8)
    _LOGGER.info('xinglongpay_withdraw create rsp: %s', response.text)
    data = json.loads(response.text)
    is_success = data.get('isSuccess', None)
    pay_id = data.get('payId', None)
    if is_success and pay_id:
        order.status = WITHDRAW_ORDER_STATUS.THIRD
        order.third_id = str(pay_id)
        order.extra_info = response.content
        order.save()
        return True
    else:
        order.detail = data.get('error', '')
        order.status = WITHDRAW_ORDER_STATUS.THIRD_FAIL
        order.extra_info = response.content
        order.save()
        return False


def check_notify_sign(request):
    """兴隆回调"""
    data = json.loads(request.body.decode('utf-8'))
    _LOGGER.info('data >>>>>>>>>>>>>>>%s' % data)
    app_id = data['accessKey']
    api_key = _get_api_key(app_id)
    _LOGGER.info("xinglongpay_withdraw notify body: %s", request.body)
    verify_notify_sign(data, api_key)
    pay_id = int(data['remark'])
    if not pay_id:
        _LOGGER.error("fatal error, mch_order_no not exists, data: %s", data)
        raise ParamError('xinglongpay_withdraw event does not contain pay ID')
    order = withdraw_db.get_order(pay_id)
    if not order or order.status != WITHDRAW_ORDER_STATUS.THIRD:
        _LOGGER.info('xinglongpay_withdraw notify order not valid: %s ', pay_id)
        raise ParamError('xinglongpay_withdraw event order not valid: %s' % pay_id)

    # Success（成功），Pendding（未处理），Processing（处理中），Fail(失败)，Refunded(已退款)
    if data['status'] == 'Pendding' or data['status'] == 'Processing':
        order.status = WITHDRAW_ORDER_STATUS.THIRD
        order.extra_info = request.body
        order.third_notify_at = datetime.utcnow()
        order.save()
    elif data['status'] == 'Fail' or data['status'] == 'Refunded':
        order.status = WITHDRAW_ORDER_STATUS.THIRD_FAIL
        order.extra_info = request.body
        order.third_notify_at = datetime.utcnow()
        order.save()
    elif data['status'] == 'Success':
        order.status = WITHDRAW_ORDER_STATUS.DONE
        order.extra_info = request.body
        order.third_notify_at = datetime.utcnow()
        order.save()
        _LOGGER.info("xinglongpay_withdraw success mch_id: %s, order_id: %s", order.mch_id, order.id)
        notify_success, _ = mch_handler.notify_mch_withdraw(order)
        if not notify_success:
            submit_notify_event(order, TIMER_EVENT_TYPE.MCH_WITHDRAW_NOTIFY)


def query_order(order, channel):
    """兴隆查询"""
    app_id = channel.appid
    parameter_dict = {
        "accessKey": app_id,
        "payId": order.third_id,
        "timestamp": int(time.time())
    }
    parameter_dict['sign'] = generate_sign(parameter_dict, _get_api_key(app_id))
    _LOGGER.info('xinglongpay_withdraw query_order data: %s', json.dumps(parameter_dict))
    url = _get_query_gateway(app_id) + '?' + _build_query_string(parameter_dict)
    _LOGGER.info('xinglongpay_withdraw query_order url: %s', url)
    response = requests.get(url, timeout=5)
    _LOGGER.info('xinglongpay_withdraw query_order rsp: %s', response.text)
    if response.status_code != 200:
        return
    order = withdraw_db.get_order(order.id)
    data = json.loads(response.text)
    # Success（成功），Pendding（未处理），Processing（处理中），Fail(失败)，Refunded(已退款)
    if data['status'] == 'Fail' or data['status'] == 'Refunded':
        order.status = WITHDRAW_ORDER_STATUS.THIRD_FAIL
        order.extra_info = response.text
        order.save()
        return
    if data['status'] != 'Success':
        return
    order.status = WITHDRAW_ORDER_STATUS.DONE
    order.extra_info = response.text
    order.save()
    if data.get('account_number'):
        bank_db.update_real_balance(data['account_number'], data['card_balance'])
    _LOGGER.info("xinglongpay_withdraw success mch_id: %s, order_id: %s", order.mch_id, order.id)
    notify_success, _ = mch_handler.notify_mch_withdraw(order)
    if not notify_success:
        submit_notify_event(order, TIMER_EVENT_TYPE.MCH_WITHDRAW_NOTIFY)
